import os.path
import requests as rq

from threading import Thread,Event
from io import BytesIO
from PIL import Image
from urllib.parse import urlsplit
from requests.packages import urllib3
from lxml import etree

from core.setting import BASEMODSURL, HEADERS, COMMUNITYURL, ICONURL

with open('setting','r',encoding='utf-8') as data:
    lines = data.readlines()
    IMGLOADTHREADCOUNT = eval(lines[2].split('=')[1].replace('\n', ''))

def isSteamUrl(url:str) -> bool:
    if url.startswith(BASEMODSURL):
        return True
    return False

def getSourceCode(url:str,is_verify=True) -> str | None:
    # 忽略警告
    urllib3.disable_warnings()
    # 关闭verify安全验证 由于国内原因上steam工坊需要科学上网造成ssl证书问题
    try:
        site = rq.get(url,headers=HEADERS,verify=is_verify,timeout=(120,100))
        if site.status_code == 200:
            text = site.text

            return text
    except:
        return None


def getParseObject(text:str) -> etree._Element | None:
    if text is None:
        return None

    parser = etree.HTMLParser(encoding='utf-8')
    # 将str转换成解析对象
    html = etree.HTML(text,parser)
    return html

def isCollect(object:etree._Element) -> bool:
    try:
        positions_div = object.xpath('//div[@id="responsive_page_template_content"]//div[@class="breadcrumbs"]')[0]
        routes_text = positions_div.xpath('a/text()')
    except IndexError:
        routes_text = []
    if '合集' in routes_text:
        return True
    return False

def getGameID(object:etree._Element) -> str:
    try:
        initial_path = object.xpath('//div[@id="responsive_page_template_content"]//div[@class="breadcrumbs"]/a[1]')[0]
        url = initial_path.attrib['href']
    except IndexError:
        url = ''
    return url.replace(COMMUNITYURL,'')

def getModsID(object:etree._Element) -> tuple:
    # xpath模糊匹配以xx开头：starts-with
    a = object.xpath('//a[starts-with(@id,"SubscribeItemBtn")]')

    return tuple([i.attrib['onclick'].replace(' ','').split("'")[1] for i in a])

def updateModTime(object:etree._Element) -> str:
    from time import strftime

    state_div = object.xpath('//div[@id="mainContents"]//div[@class="detailsStatsContainerRight"]/div')
    if len(state_div) < 3:
        time = state_div[1].text .replace(' ','')
    else:
        time = state_div[2].text.replace(' ','')

    if '年' not in time:
        time = f'{strftime("%Y")}年' + time

    return time

def getIcon(url:str):
    urllib3.disable_warnings()
    parser_url = urlsplit(url)
    netloc = parser_url.netloc
    icon_url = parser_url.scheme + '://' + netloc + ICONURL
    savePath = f'./img/{netloc.replace(".","_")}.ico'
    if not os.path.exists(savePath):
        img = Image.open(BytesIO(rq.get(icon_url,headers=HEADERS,verify=False).content))
        if img.width < 64 or img.height < 64:
            img = img.resize((64,64))
        img.save(savePath,sizes=[(64,64)])
    return netloc.replace(".","_")

def getTitle(url:str,object=None) -> str:
    if object is None:
        object = getParseObject(getSourceCode(url,is_verify=False))

    if object is None:
        return '重命名'

    return (object.xpath('/html/head/title/text()') or ['重命名'])[0]

def getModName(url:str=None,object=None,isCollectItem:bool=None) -> list:
    if object is None:
        object = getParseObject(getSourceCode(url,is_verify=False))

    if object == None:
        return []

    if isCollectItem is None:
        isCollectItem = isCollect(object)

    if isCollectItem:
        return object.xpath('//*[@class="collectionChildren"]//div[@class="collectionItem"]//div[@class="workshopItemTitle"]/text()')
    else:
        return object.xpath('//*[@id="profileBlock"]/div/div[1]/div/h1/text()')

def downloadImgs(result:dict,imgs:list,startIndex:int=0,event:Event=None) -> dict | None:
    for index,imgUrl in enumerate(imgs,start=startIndex):
        if event is not None and event.is_set():
            return

        imgLst = imgUrl.split('/')
        fileName = imgLst[imgLst.index('ugc') + 1] + '.jpg'

        if not os.path.exists(f'./imgCache/{fileName}'):
            re = rq.get(imgUrl,verify=False)
            with open(f'./imgCache/{fileName}','wb') as data:
                data.write(re.content)

        result[index] = fileName

    return result

def getModIcon(url:str=None,object=None,isCollectItem:bool=None,event:Event=None):
    if object is None:
        object = getParseObject(getSourceCode(url,is_verify=False))

    if object == None:
        return

    if isCollectItem is None:
        isCollectItem = isCollect(object)

    if isCollectItem:
        imgs = object.xpath('//*[@class="collectionChildren"]//div[@class="collectionItem"]//div[@class="workshopItem"]//img[@class="workshopItemPreviewImage"]/@src')
    else:
        imgs = object.xpath('//img[@id="previewImageMain"]/@src')

    if event is not None and event.is_set():
        return

    result = {}
    imgCount = len(imgs)
    imgDTC = IMGLOADTHREADCOUNT
    remainder = imgCount%imgDTC
    threadings = []

    for start,end in enumerate(range(1,imgCount//imgDTC+1)):
        if event is not None and event.is_set():
            return
        currentImgs = imgs[start*imgDTC:imgDTC*end]
        currentThreading = Thread(target=downloadImgs,
                                  name=f'imgDownload_{imgDTC*end}',
                                  args=(result,currentImgs,),
                                  kwargs={'startIndex':start*imgDTC,'event':event},
                                  daemon=True)
        currentThreading.start()
        threadings.append(currentThreading)

    downloadImgs(result,imgs[-remainder:],startIndex=imgCount-remainder)

    while threadings:
        if event is not None and event.is_set():
            return
        for threading in threadings:
            if not threading.is_alive():
                threadings.remove(threading)

    return result